home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / pctjoc85.arc / SLIMFISH.PAS < prev    next >
Pascal/Delphi Source File  |  1985-03-11  |  22KB  |  818 lines

  1. { WA-TOR program -- Inspired by Scientific American, 12/84 }
  2.  
  3. {$debug-}
  4. {$entry-}
  5. {$line-}
  6.  
  7. PROGRAM wator(input,output) ;
  8.  
  9.   { ms-pascal library functions }
  10.  
  11.   FUNCTION dosxqq(command: byte; parm: word): byte ;
  12.     EXTERN ;
  13.  
  14.   { assembly language utilities }
  15.  
  16.   PROCEDURE set_cursor(row,column: integer) ;
  17.     EXTERN ;
  18.  
  19.   PROCEDURE cursor_disappear ;
  20.     EXTERN ;
  21.  
  22.   PROCEDURE cursor_reappear ;
  23.     EXTERN ;
  24.  
  25.   PROCEDURE clear_screen ;
  26.     EXTERN ;
  27.  
  28.   TYPE
  29.     byte_address = ads of byte ;
  30.  
  31.   PROCEDURE blast_video_ram(address: byte_address ;
  32.                             output_byte: byte) ;
  33.     EXTERN ;
  34.  
  35.   FUNCTION equipment: word ;
  36.     EXTERN ;
  37.  
  38.   FUNCTION tics : word ;
  39.     EXTERN ;
  40.  
  41.   PROCEDURE install_break_handler ;
  42.     EXTERN ;
  43.  
  44.   FUNCTION check_break : boolean ;
  45.     EXTERN ;
  46.  
  47.   PROCEDURE remove_break_handler ;
  48.     EXTERN ;
  49.  
  50.   CONST
  51.  
  52.     { video attributes }
  53.  
  54.     normal = 7 ;
  55.     intense = 15 ;
  56.  
  57.     { keyboard codes }
  58.  
  59.     enter = #D ;
  60.     backspace = #8 ;
  61.     blank = #20 ;
  62.  
  63.     { describe the size of the wator world }
  64.  
  65.     xsize = 79 ;                       { horizontal size of wator  }
  66.     maxx = 78 ;                        { xsize -1                  }
  67.     ysize = 20 ;                       { vertical size of wator    }
  68.     maxy = 19 ;                        { ysize -1                  }
  69.     max_beings = (xsize*ysize)+4 ;     { maximum beings of wator   }
  70.  
  71.   TYPE
  72.  
  73.     { describe the fish lists used to keep track of wator's beings }
  74.  
  75.     species = (fish,shark,empty) ;
  76.     xcoord = 0..maxx ;
  77.     ycoord = 0..maxy ;
  78.     link = ADR of fishes ;
  79.     fishes = RECORD
  80.                next : link ;
  81.                prev : link ;
  82.                kind : species ;
  83.                age : integer ;
  84.                x : xcoord ;
  85.                y : ycoord ;
  86.                ate : integer ;
  87.              END ;
  88.  
  89.     { identify the neighbors of a given fish or shark }
  90.  
  91.     neighbor = RECORD
  92.                  x : integer ;
  93.                  y : integer ;
  94.                  kind : species ;
  95.                END ;
  96.     neighborhood = ARRAY [1..8] OF neighbor ;
  97.  
  98.     { video screen types }
  99.  
  100.     video_position = RECORD
  101.                        character: char ;
  102.                        attribute: byte ;
  103.                      END;
  104.     video_ram_type = ARRAY [1..25,1..80] of video_position ;
  105.  
  106.   VAR
  107.  
  108.     { free pool of sharks and fishes }
  109.  
  110.     free_pool : ARRAY [1..max_beings] of fishes ;
  111.  
  112.     { head free pool of sharks and fishes }
  113.  
  114.     free_pool_head : link ;
  115.  
  116.     { heads and tails of the lists of beings on wator }
  117.  
  118.     fish_head : link ;
  119.     fish_tail : link ;
  120.     shark_head : link ;
  121.     shark_tail : link ;
  122.  
  123.     { array to identify what is currently at a place in wator }
  124.  
  125.     pond : ARRAY [xcoord,ycoord] OF species ;
  126.  
  127.     { variables that describe the characteristics of wator }
  128.  
  129.     nfishes : integer ;           { init number of fishes in pond  }
  130.     nsharks : integer ;           { init number of sharks in pond  }
  131.     sbreed : integer ;            { chronons btwn shark breeding   }
  132.     fbreed : integer ;            { chronons btwn fish  breeding   }
  133.     starve : integer ;            { time a shark can go w/o eating }
  134.  
  135.     { miscellaneous variables }
  136.  
  137.     generation : integer ;
  138.     counts : ARRAY [fish..shark] OF integer ;
  139.     neighbors : ARRAY [1..4] OF neighbor ;
  140.     abort : boolean ;
  141.     seed : word ;
  142.     monochrome_adapter : boolean ;
  143.     video_ram : ADS of video_ram_type ;
  144.     screen_string : lstring(80) ;
  145.  
  146.     { interface to pascal's runtime ctrl to manage data seg size   }
  147.  
  148.     datsqq [PUBLIC] : word;       { size of wator's data segment   }
  149.  
  150.   VALUE
  151.  
  152.     { maximum size of pascal's data segment in paragraphs }
  153.  
  154.     datsqq := 1536;               { 1536 paragraphs = 24K bytes    }
  155.  
  156.   { utility to concatenate two strings together }
  157.  
  158.   PROCEDURE concat_string(var target: lstring ;
  159.                           const source: string) ;
  160.     VAR
  161.       length : integer ;
  162.       i: integer ;
  163.  
  164.     BEGIN
  165.       length := upper(source) ;
  166.       IF length > upper(target) - ord(target.len) THEN
  167.         length := upper(target) - ord(target.len) ;
  168.       IF length <> 0 THEN
  169.         BEGIN
  170.           FOR i := 1 to length DO
  171.             target[ord(target.len) + i] := source[i] ;
  172.           target.len := target.len + wrd(length) ;
  173.         END ;
  174.     END ;
  175.  
  176.   { utility to concatenate an integer to a string }
  177.  
  178.   PROCEDURE concat_integer_to_string(var target: lstring;
  179.                                      source: integer) ;
  180.  
  181.     VAR
  182.       i : integer ;
  183.       temp : integer4 ;
  184.       new_char : char ;
  185.  
  186.     BEGIN
  187.       IF source < 0 THEN
  188.         concat_string(target,'0')
  189.       ELSE
  190.         BEGIN
  191.           temp := 100000000 ;
  192.           WHILE temp > source DO
  193.             temp := temp DIV 10 ;
  194.           WHILE temp > 1 DO
  195.             BEGIN
  196.               new_char := chr(ord(source DIV temp) + ord('0')) ;
  197.               concat_string(target,new_char) ;
  198.               source := ord(source MOD temp) ;
  199.               temp := temp DIV 10 ;
  200.             END ;
  201.           new_char := chr(ord(source) + ord('0')) ;
  202.           concat_string(target,new_char) ;
  203.       END ;
  204.     END ;
  205.  
  206.   { utility to convert a string into an integer }
  207.  
  208.   FUNCTION string_to_integer(const source: string): integer ;
  209.  
  210.     VAR
  211.       i,n : integer ;
  212.  
  213.     BEGIN
  214.       n := 0 ;
  215.       FOR i := 1 TO upper(source) DO
  216.         BEGIN
  217.           IF (source[i] < '0') OR (source[i] > '9') THEN
  218.             BEGIN
  219.               string_to_integer := 0 ;
  220.               RETURN ;
  221.             END ;
  222.           n := n * 10 + ord(source[i]) - ord('0') ;
  223.         END ;
  224.       string_to_integer := n ;
  225.     END ;
  226.  
  227.   { screen display utility }
  228.  
  229.   PROCEDURE display_string(row,column : integer ;
  230.                            const output_string : lstring ;
  231.                            attrib : byte);
  232.     VAR
  233.       i : integer ;
  234.  
  235.     BEGIN
  236.  
  237.       { update monochrome adapter video ram fast w/o sync }
  238.  
  239.       IF monochrome_adapter THEN
  240.       FOR i := 1 to ord(output_string.len) DO
  241.         BEGIN
  242.           video_ram^[row,column+i-1].character := output_string[i] ;
  243.           video_ram^[row,column+i-1].attribute := attrib ;
  244.         END
  245.  
  246.       { sync while updating color adapter video ram to avoid snow }
  247.  
  248.       ELSE FOR i := 1 to ord(output_string.len) DO
  249.         BEGIN
  250.           blast_video_ram(ADS video_ram^[row,column+i-1].character,
  251.                           wrd(output_string[i])) ;
  252.           blast_video_ram(ADS video_ram^[row,column+i-1].attribute,
  253.                           attrib) ;
  254.         END ;
  255.     END ;
  256.  
  257.   { number display utility }
  258.  
  259.   PROCEDURE display_number(row,column,number : integer ;
  260.                            attrib : byte);
  261.     VAR
  262.       i : integer ;
  263.  
  264.     BEGIN
  265.       display_string(row,column,'      ',attrib);
  266.       screen_string := ' ';
  267.       concat_integer_to_string(screen_string,number) ;
  268.       display_string(row,column,screen_string,attrib) ;
  269.     END ;
  270.  
  271.   { utility to get the next keystroke }
  272.  
  273.   FUNCTION get_next_key : char ;
  274.  
  275.     VAR
  276.       key_code: byte;
  277.  
  278.     BEGIN
  279.       key_code := dosxqq(1,0) ;
  280.       IF (key_code = 0) THEN
  281.         key_code := dosxqq(1,0);
  282.       get_next_key := chr(key_code);
  283.     END;
  284.  
  285.   { utility to get an integer from the keyboard }
  286.  
  287.   FUNCTION get_integer: integer ;
  288.  
  289.     VAR
  290.       key: char ;
  291.       input_string: lstring(80);
  292.  
  293.     BEGIN
  294.       input_string.len := 0;
  295.       key := get_next_key ;
  296.       WHILE (key <> chr(enter)) AND (input_string.len <= 80) DO
  297.         BEGIN
  298.           IF (key = chr(backspace)) AND
  299.              (input_string.len > 0) THEN
  300.             BEGIN
  301.               eval(dosxqq(2,blank));
  302.               eval(dosxqq(2,backspace));
  303.               input_string.len := input_string.len - 1;
  304.             END
  305.           ELSE
  306.             BEGIN
  307.               input_string.len := input_string.len + 1;
  308.               input_string[ord(input_string.len)] := key;
  309.             END;
  310.           key := get_next_key ;
  311.         END;
  312.       get_integer := string_to_integer(input_string);
  313.     END;
  314.  
  315.   { random number generator }
  316.  
  317.   FUNCTION random(max_index:integer) : integer ;
  318.  
  319.     VAR
  320.       product : integer4 ;
  321.  
  322.     BEGIN
  323.       product := 1433 * ord(seed) ;
  324.       seed := wrd(product) + 1847;
  325.       random := ord(seed mod wrd(max_index)) ;
  326.     END ;
  327.  
  328.   { allocate a shark or fish from the fish pool }
  329.  
  330.   FUNCTION allocate_fish: link ;
  331.  
  332.     BEGIN
  333.       allocate_fish := free_pool_head ;
  334.       free_pool_head := free_pool_head^.next ;
  335.     END ;
  336.  
  337.   { free a shark or fish back to the fish pool }
  338.  
  339.   PROCEDURE free_fish(fish_p : link) ;
  340.  
  341.     BEGIN
  342.       fish_p^.next := free_pool_head ;
  343.       free_pool_head := fish_p ;
  344.     END ;
  345.  
  346.   { utility function to implement universe wrapping }
  347.  
  348.   FUNCTION wrap(c,l:integer) : integer ;
  349.  
  350.     BEGIN
  351.       c := c MOD l ;
  352.       IF c < 0 THEN
  353.         c := c + l ;
  354.       wrap := c ;
  355.     END ;
  356.  
  357.   { procedure to display a fish (or water) at a given location }
  358.  
  359.   PROCEDURE display_fish(x:xcoord ;
  360.                          y:ycoord ;
  361.                          t:species) ;
  362.  
  363.     BEGIN
  364.       IF t = fish THEN
  365.         BEGIN
  366.           display_string(y+1,x+1,',',normal);
  367.         END
  368.       ELSE IF t = shark THEN
  369.         BEGIN
  370.           display_string(y+1,x+1,'δ',intense);
  371.         END
  372.       ELSE
  373.         display_string(y+1,x+1,' ',normal);
  374.       pond[x,y] := t ;
  375.     END ;
  376.  
  377.   { procedure to add a new fish (or shark) to the pond }
  378.  
  379.   PROCEDURE add_fish(p:link ;
  380.                      p_kind:species ;
  381.                      p_x:xcoord ;
  382.                      p_y:ycoord) ;
  383.  
  384.     VAR
  385.       t : link ;
  386.  
  387.     BEGIN
  388.       t := allocate_fish ;
  389.       counts[p_kind] := counts[p_kind] + 1 ;
  390.       WITH t^ DO
  391.         BEGIN
  392.           next := p^.next ;
  393.           prev := p ;
  394.           kind := p_kind ;
  395.           age := 0 ;
  396.           x := p_x ;
  397.           y := p_y ;
  398.           ate := 0 ;
  399.           display_fish(p_x,p_y,p_kind) ;
  400.         END ;
  401.       p^.next^.prev := t ;
  402.       p^.next := t ;
  403.     END ;
  404.  
  405.   { procedure to delete an entry from a fish list }
  406.  
  407.   PROCEDURE delete_fish(p:link) ;
  408.  
  409.     BEGIN
  410.       WITH p^ DO
  411.         BEGIN
  412.           counts[p^.kind] := counts[p^.kind] - 1 ;
  413.           prev^.next := next ;
  414.           next^.prev := prev ;
  415.           display_fish(x,y,empty) ;
  416.           free_fish(p) ;
  417.         END ;
  418.     END ;
  419.  
  420.   { procedure to check the pond around a given fish/shark }
  421.  
  422.   PROCEDURE check_pond(p_x:xcoord ;
  423.                        p_y:ycoord ;
  424.                        t:species ;
  425.                        VAR n:integer ;
  426.                        VAR a:neighborhood) ;
  427.  
  428.     VAR
  429.       tx : xcoord ;
  430.       ty : ycoord ;
  431.       i : integer ;
  432.  
  433.     BEGIN
  434.       n := 0 ;
  435.       FOR i := 1 TO 4 DO
  436.         BEGIN
  437.           tx := wrap(p_x+neighbors[i].x,xsize) ;
  438.           ty := wrap(p_y+neighbors[i].y,ysize) ;
  439.           IF pond[tx,ty] = t THEN
  440.             BEGIN
  441.               n := n + 1 ;
  442.               WITH a[n] DO
  443.                 BEGIN
  444.                   x := tx ;
  445.                   y := ty ;
  446.                   kind := pond[tx,ty] ;
  447.                 END ;
  448.             END ;
  449.         END ;
  450.     END ;
  451.  
  452.   { procedure to make fish swim }
  453.  
  454.   PROCEDURE fish_swim ;
  455.  
  456.     VAR
  457.       f_link : link ;
  458.       f_n : integer ;
  459.       f_nghbr : neighborhood ;
  460.       old_x : xcoord ;
  461.       old_y : ycoord ;
  462.       r : integer ;
  463.  
  464.     BEGIN
  465.       f_link := fish_head^.next ;
  466.       WHILE (f_link <> fish_tail) DO
  467.         WITH f_link^ DO
  468.           BEGIN
  469.             IF check_break THEN
  470.               BEGIN
  471.                 abort := true ;
  472.                 break ;
  473.               END;
  474.             check_pond(x,y,empty,f_n,f_nghbr) ;
  475.             IF f_n > 0 THEN
  476.               BEGIN
  477.                 old_x := x ;
  478.                 old_y := y ;
  479.                 r := random(f_n) + 1 ;
  480.                 display_fish(x,y,empty) ;
  481.                 x := f_nghbr[r].x ;
  482.                 y := f_nghbr[r].y ;
  483.                 display_fish(x,y,fish) ;
  484.                 IF age >= fbreed THEN
  485.                   BEGIN
  486.                     add_fish(fish_head,fish,old_x,old_y) ;
  487.                     age := 0 ;
  488.                   END
  489.                 ELSE
  490.                   age := age + 1 ;
  491.               END
  492.             ELSE
  493.               age := age + 1 ;
  494.             f_link := next ;
  495.           END ;
  496.     END ;
  497.  
  498.   { procedure where a fish turns into a shark nummy }
  499.  
  500.   PROCEDURE eat_fish(p_x:xcoord ;
  501.                      p_y:ycoord) ;
  502.  
  503.     VAR
  504.       f_link : link ;
  505.       eaten : boolean ;
  506.  
  507.     BEGIN
  508.       eaten := false ;
  509.       f_link := fish_head^.next ;
  510.       WHILE (f_link<>fish_tail) AND ( NOT eaten) DO
  511.         WITH f_link^ DO
  512.           IF (x = p_x) AND (y = p_y) THEN
  513.             BEGIN
  514.               delete_fish(f_link) ;
  515.               eaten := true ;
  516.             END
  517.           ELSE
  518.             f_link := next ;
  519.     END ;
  520.  
  521.   { shark hunt and breeding procedure }
  522.  
  523.   PROCEDURE shark_move ;
  524.  
  525.     LABEL
  526.       next_shark ;
  527.  
  528.     VAR
  529.       s_link : link ;
  530.       s_n : integer ;
  531.       s_nghbr : neighborhood ;
  532.       old_x : xcoord ;
  533.       old_y : ycoord ;
  534.       r : integer ;
  535.  
  536.     BEGIN
  537.       s_link := shark_head^.next ;
  538.       WHILE (s_link <> shark_tail) DO
  539.         WITH s_link^ DO
  540.           BEGIN
  541.             IF check_break THEN
  542.               BEGIN
  543.                 abort := true;
  544.                 break;
  545.               END;
  546.  
  547.             { feeding section }
  548.  
  549.             check_pond(x,y,fish,s_n,s_nghbr) ;
  550.             IF s_n > 0 THEN
  551.               BEGIN
  552.                 old_x := x ;
  553.                 old_y := y ;
  554.                 r := random(s_n) + 1 ;
  555.                 display_fish(x,y,empty) ;
  556.                 x := s_nghbr[r].x ;
  557.                 y := s_nghbr[r].y ;
  558.                 eat_fish(x,y) ;
  559.                 display_fish(x,y,shark) ;
  560.                 ate := 0 ;
  561.                 IF age >= sbreed THEN
  562.                   BEGIN
  563.                     add_fish(shark_head,shark,old_x,old_y) ;
  564.                     age := 0 ;
  565.                   END
  566.                 ELSE
  567.                   age := age + 1 ;
  568.                 s_link := next ;
  569.                 GOTO next_shark ;
  570.               END ;
  571.  
  572.             { starvation section }
  573.  
  574.             ate := ate + 1 ;
  575.             IF ate > starve THEN
  576.               BEGIN
  577.                 screen_string := 'shark at position (';
  578.                 concat_integer_to_string(screen_string,y+1);
  579.                 concat_string(screen_string,',');
  580.                 concat_integer_to_string(screen_string,x+1);
  581.                 concat_string(screen_string,') starved...');
  582.                 display_string(ysize+5,41,screen_string,normal);
  583.                 s_link := next ;
  584.                 delete_fish(s_link^.prev) ;
  585.                 GOTO next_shark ;
  586.               END ;
  587.  
  588.             { move to unoccupied section }
  589.  
  590.             check_pond(x,y,empty,s_n,s_nghbr) ;
  591.             IF s_n > 0 THEN
  592.               BEGIN
  593.                 old_x := x ;
  594.                 old_y := y ;
  595.                 r := random(s_n) + 1 ;
  596.                 display_fish(x,y,empty) ;
  597.                 x := s_nghbr[r].x ;
  598.                 y := s_nghbr[r].y ;
  599.                 display_fish(x,y,shark) ;
  600.                 IF age >= sbreed THEN
  601.                   BEGIN
  602.                     add_fish(shark_head,shark,old_x,old_y) ;
  603.                     age := 0 ;
  604.                   END
  605.                 ELSE
  606.                   age := age + 1 ;
  607.                 s_link := next ;
  608.                 GOTO next_shark ;
  609.               END ;
  610.  
  611.             { if we get here, the shark just gets older }
  612.  
  613.             age := age + 1 ;
  614.             s_link := next ;
  615.             GOTO next_shark ;
  616. next_shark:
  617.           END ;
  618.     END ;
  619.  
  620.   { wator initialization procedure }
  621.  
  622.   PROCEDURE init_wator ;
  623.  
  624.     VAR
  625.       i : integer ;
  626.       tx : xcoord ;
  627.       ty : ycoord ;
  628.       tt : boolean ;
  629.  
  630.     BEGIN
  631.       display_string(1,1,'Welcome to WA-TOR.',normal) ;
  632.       display_string(3,1,'How many fishes does WA-TOR have?',
  633.                      normal) ;
  634.       display_string(4,1,'Pick a number between 1..1000.  Try 200.',
  635.                      normal) ;
  636.       set_cursor(4,0);
  637.       i := get_integer;
  638.       IF (i>1000) OR (i<1) THEN
  639.         nfishes := 200
  640.       ELSE
  641.         nfishes := i ;
  642.  
  643.       display_string(6,1,'How many sharks does WA-TOR have?',
  644.                      normal) ;
  645.       display_string(7,1,'Pick a number between 1..200.  Try 20.',
  646.                      normal) ;
  647.       set_cursor(7,0);
  648.       i := get_integer;
  649.       IF (i>200) OR (i<1) THEN
  650.         nsharks := 20
  651.       ELSE
  652.         nsharks := i ;
  653.  
  654.       display_string(9,1,'How often do the fish breed?',normal) ;
  655.       display_string(10,1,
  656.         'Pick a number between 1..100 chronons.  Try 3 chronons.',
  657.                      normal) ;
  658.       set_cursor(10,0);
  659.       i := get_integer;
  660.       IF (i>100) OR (i<1) THEN
  661.         fbreed := 3
  662.       ELSE
  663.         fbreed := i ;
  664.  
  665.       display_string(12,1,'How often do the sharks breed?',normal) ;
  666.       display_string(13,1,
  667.         'Pick a number between 1..100 chronons.  Try 10 chronons.',
  668.                      normal) ;
  669.       set_cursor(13,0);
  670.       i := get_integer;
  671.       IF (i>100) OR (i<1) THEN
  672.         sbreed := 10
  673.       ELSE
  674.         sbreed := i ;
  675.  
  676.       display_string(15,1,'How long can a shark go without eating?',
  677.                      normal) ;
  678.       display_string(16,1,
  679.         'Pick a number between 1..100 chronons.  Try 3 chronons.',
  680.                      normal) ;
  681.       set_cursor(16,0);
  682.       i := get_integer;
  683.       IF (i>100) OR (i<1) THEN
  684.         starve := 3
  685.       ELSE
  686.         starve := i ;
  687.       cursor_disappear;
  688.       clear_screen;
  689.       display_string(ysize+2,1,'fishes     =',normal);
  690.       display_string(ysize+3,1,'sharks     =',normal);
  691.       display_string(ysize+4,1,'generation =',normal);
  692.  
  693.       screen_string := 'fish breed every ';
  694.       concat_integer_to_string(screen_string,fbreed);
  695.       concat_string(screen_string,' chronons');
  696.       display_string(ysize+2,41,screen_string,normal);
  697.  
  698.       screen_string := 'sharks breed every ';
  699.       concat_integer_to_string(screen_string,sbreed);
  700.       concat_string(screen_string,' chronons');
  701.       display_string(ysize+3,41,screen_string,normal);
  702.  
  703.       screen_string := 'sharks starve after ';
  704.       concat_integer_to_string(screen_string,starve);
  705.       concat_string(screen_string,' chronons');
  706.       display_string(ysize+4,41,screen_string,normal);
  707.  
  708.       display_string(ysize+5,1,'Press Ctrl-Break to end WA-TOR...',
  709.                      normal) ;
  710.       abort := false;
  711.       seed := tics ;
  712.       neighbors[1].x := 0 ;
  713.       neighbors[1].y := - 1 ;
  714.       neighbors[2].x := - 1 ;
  715.       neighbors[2].y := 0 ;
  716.       neighbors[3].x := 1 ;
  717.       neighbors[3].y := 0 ;
  718.       neighbors[4].x := 0 ;
  719.       neighbors[4].y := 1 ;
  720.  
  721.       { initialize free list of sharks and fishes }
  722.  
  723.       free_pool_head := ADR free_pool[1] ;
  724.       FOR i := 1 to (max_beings-1) DO
  725.           free_pool[i].next := ADR free_pool[i+1] ;
  726.  
  727.       { setup allocated lists of sharks and fishes }
  728.  
  729.       fish_head := allocate_fish ;
  730.       fish_tail := allocate_fish ;
  731.       shark_head := allocate_fish ;
  732.       shark_tail := allocate_fish ;
  733.       fish_head^.next := fish_tail ;
  734.       fish_tail^.prev := fish_head ;
  735.       shark_head^.next := shark_tail ;
  736.       shark_tail^.prev := shark_head ;
  737.       counts[fish] := 0 ;
  738.       counts[shark] := 0 ;
  739.       generation := 1 ;
  740.       FOR tx := 0 TO maxx DO
  741.         FOR ty := 0 TO maxy DO
  742.           pond[tx,ty] := empty ;
  743.       FOR i := 1 TO nfishes DO
  744.         BEGIN
  745.           tt := true ;
  746.           WHILE tt DO
  747.             BEGIN
  748.               tx := random(xsize) ;
  749.               ty := random(ysize) ;
  750.               IF pond[tx,ty] = empty THEN
  751.                 BEGIN
  752.                   add_fish(fish_head,fish,tx,ty) ;
  753.                   fish_head^.next^.age := random(fbreed) ;
  754.                   tt := false ;
  755.                 END ;
  756.             END ;
  757.         END ;
  758.       FOR i := 1 TO nsharks DO
  759.         BEGIN
  760.           tt := true ;
  761.           WHILE tt DO
  762.             BEGIN
  763.               tx := random(xsize) ;
  764.               ty := random(ysize) ;
  765.               IF pond[tx,ty] = empty THEN
  766.                 BEGIN
  767.                   add_fish(shark_head,shark,tx,ty) ;
  768.                   WITH shark_head^.next^ DO
  769.                     BEGIN
  770.                       age := random(sbreed) ;
  771.                       ate := random(starve) ;
  772.                     END ;
  773.                   tt := false ;
  774.                 END ;
  775.             END ;
  776.         END ;
  777.     END ;
  778.  
  779.   { hardware initialization procedure }
  780.  
  781.   PROCEDURE init_hardware ;
  782.  
  783.     BEGIN
  784.       clear_screen ;
  785.       set_cursor(0,0) ;
  786.       monochrome_adapter := ((equipment AND 16#30) = 16#30) ;
  787.       IF monochrome_adapter THEN
  788.         video_ram.s := 16#B000
  789.       ELSE video_ram.s := 16#B800 ;
  790.       video_ram.r := 0 ;
  791.     END ;
  792.  
  793.   { main program }
  794.  
  795.   BEGIN
  796.     init_hardware ;
  797.     init_wator ;
  798.     install_break_handler ;
  799.     WHILE ((fish_head^.next <> fish_tail) OR
  800.           (shark_head^.next <> shark_tail)) AND
  801.           (NOT abort) DO
  802.       BEGIN
  803.         display_number(ysize+2,14,counts[fish],normal);
  804.         display_number(ysize+3,14,counts[shark],normal);
  805.         display_number(ysize+4,14,generation,normal);
  806.         fish_swim ;
  807.         shark_move ;
  808.         generation := generation + 1 ;
  809.       END;
  810.     remove_break_handler ;
  811.     clear_screen ;
  812.     IF (fish_head^.next = fish_tail) AND
  813.        (shark_head^.next = shark_tail) THEN
  814.       display_string(1,1,'All life on WA-TOR extinct...',normal) ;
  815.     set_cursor(0,0) ;
  816.     cursor_reappear ;
  817.   END.
  818.